﻿using System;
using Cysharp.Threading.Tasks;
using UnityEngine;
using Object = UnityEngine.Object;

namespace uMVP
{
    /// <summary>
    /// 视图资源初始化
    /// </summary>
    public interface IViewResourceInitializer
    {
        void InitializePrefabInstance(string prefabPath, string parentPath);
    }

    public abstract class ViewBase : IView, IViewResourceInitializer
    {
        protected GameObject ViewGameObject;

        public void InitializePrefabInstance(string prefabPath, string parentPath)
        {
            CreateViewGameObject(prefabPath);
            SetViewGameObjectParent(parentPath);
        }

        public virtual void Destroy()
        {
            CloseAsync().Forget();
            OnDestroy();
            Object.Destroy(ViewGameObject);
        }

        protected virtual string GetPrefabPath()
        {
            return "";
        }

        private void CreateViewGameObject(string prefabPath)
        {
            if (string.IsNullOrEmpty(prefabPath))
            {
                var path = GetPrefabPath();
                if (string.IsNullOrEmpty(path))
                    return;
                prefabPath = path;
            }

            var prefab = Resources.Load<GameObject>(prefabPath);
            if (prefab == null)
                throw new Exception($"预制体路径错误，请检查预制体路径，prefabPath:{prefabPath}");

            ViewGameObject = Object.Instantiate(prefab);
        }

        private void SetViewGameObjectParent(string parentPath)
        {
            if (string.IsNullOrEmpty(parentPath))
                return;

            var parent = GameObject.Find(parentPath);
            if (parent == null)
                throw new Exception($"没找到指定路径对应的父节点， 请检查路径是否正确，parentPath:{parentPath}");
            ViewGameObject.transform.SetParent(parent.transform, false);
        }

        public virtual async UniTask OpenAsync()
        {
            if (ViewGameObject != null)
                ViewGameObject.SetActive(true);
            await OnOpenAsync();
        }

        public virtual async UniTask CloseAsync()
        {
            await OnCloseAsync();
            if (ViewGameObject != null)
                ViewGameObject.SetActive(false);
        }

        public abstract UniTask OnInitializeAsync();
        public abstract void OnDestroy();

        protected virtual UniTask OnOpenAsync()
        {
            return UniTask.CompletedTask;
        }

        protected virtual UniTask OnCloseAsync()
        {
            return UniTask.CompletedTask;
        }
    }

    public abstract class ViewBase<TPresenterInterface, TPresenterFactory> :
        ViewBase,
        IView<TPresenterInterface, TPresenterFactory>
        where TPresenterInterface : class
        where TPresenterFactory : Delegate
    {
        public TPresenterInterface Presenter { get; private set; }

        public void SetPresenter(TPresenterInterface presenter)
        {
            Presenter = presenter;
        }

        public override void Destroy()
        {
            base.Destroy();
            (Presenter as IPresenter)?.Destroy();
        }

        public override async UniTask OpenAsync()
        {
            await base.OpenAsync();
            await GetPresenter().OpenAsync();
        }

        public override async UniTask CloseAsync()
        {
            await base.CloseAsync();
            await GetPresenter().CloseAsync();
        }

        private IPresenter GetPresenter()
        {
            if (Presenter == null)
                throw new NullReferenceException("Presenter实例为空");
            
            var p = Presenter as IPresenter;
            if (p == null)
                throw new NullReferenceException($"接口:{typeof(TPresenterInterface)}, 没有继承 IPresenter");
            return p;
        }

        public abstract TPresenterInterface OnCreatePresenter(TPresenterFactory factory);
    }

    public abstract class ViewBase<TPresenterInterface> :
        ViewBase<TPresenterInterface, Func<IView<TPresenterInterface>, TPresenterInterface>>
        where TPresenterInterface : class
    {
        public override TPresenterInterface OnCreatePresenter(
            Func<IView<TPresenterInterface>, TPresenterInterface> factory)
        {
            if (factory == null)
                throw new ArgumentNullException(nameof(factory));

            return factory(this);
        }
    }
}